package socket.nio.demo_01;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.Iterator;
import java.util.Set;

/**
 * 非阻塞的chargen服务器
 */
public class ChargenServer {
    public static int port = 1024;

    public static void main(String[] args) {
        byte[]  rotation = new byte[95 * 2];
        for (byte i = ' '; i <= '~'; i++) {
            rotation[i - ' '] = i;
            rotation[i + 95 - ' '] = i;
        }

        ServerSocketChannel serverChannel;
        Selector selector;

        try {
            // jdk1.7 之后 serverChannel.bind(new InetSocketAddress(port))
            serverChannel = ServerSocketChannel.open();
            ServerSocket ss = serverChannel.socket();
            ss.bind(new InetSocketAddress(port));

            // 非阻塞模式
            serverChannel.configureBlocking(false);
            // 创建一个Selector， 允许程序迭代处理所有准备好的连接
            selector = Selector.open();
            serverChannel.register(selector, SelectionKey.OP_ACCEPT);
        } catch (IOException e) {
            e.printStackTrace();
            return;
        }

        while(true) {
            try {
                // 为了检查是否有可操作的数据，可以调用选择器的select()方法。对于长时间运行的服务器，一般放在一个无限循环中
                selector.select();
            } catch (IOException e) {
                e.printStackTrace();
                break;
            }

            // 假定选择器找到了一个就绪的通道，其selectedKeys()方法会返回一个java.util.Set
            Set<SelectionKey> readyKeys = selector.selectedKeys();
            Iterator<SelectionKey> iterator = readyKeys.iterator();
            while(iterator.hasNext()) {
                SelectionKey key = iterator.next();
                iterator.remove();
                try {
                    if(key.isAcceptable()) {
                        ServerSocketChannel server = (ServerSocketChannel) key.channel();
                        SocketChannel client = server.accept();
                        System.out.println("Accepted connection from " + client);
                        client.configureBlocking(false);
                        SelectionKey key2 = client.register(selector, SelectionKey.OP_WRITE);
                        ByteBuffer buffer = ByteBuffer.allocate(74);
                        buffer.put(rotation, 0, 72);
                        buffer.put((byte) '\r');
                        buffer.put((byte) '\n');
                        buffer.flip();
                        key2.attach(buffer);
                    } else if(key.isWritable()) {
                        SocketChannel client = (SocketChannel) key.channel();
                        ByteBuffer buffer = (ByteBuffer) key.attachment();
                        if(!buffer.hasRemaining()) {
                            // 用下一行重新填充缓冲区
                            buffer.rewind();
                            // 得到上一次的首字母
                            int first = buffer.get();
                            // 准备改变缓冲区中的数据
                            buffer.rewind();
                            // 寻找rotation中新的首字符位置
                            int position = first - ' ' + 1;
                            // 将数据从rotation复制到缓冲区
                            buffer.put(rotation, position, 72);
                            // 在缓冲区末尾存储一个行分隔符
                            buffer.put((byte) '\r');
                            buffer.put((byte) '\n');
                            // 准备缓冲区进行写入
                            buffer.flip();
                        }

                        client.write(buffer);
                    }
                } catch (IOException e) {
                    key.cancel();
                    try{
                        key.channel().close();
                    } catch (IOException e1) {
                        e1.printStackTrace();
                    }
                }
            }
        }
    }
}
